﻿using System;
using System.Collections.Generic;
using System.Linq;
using Engine;

namespace Game
{
    public class newTerrainContentsGenerator : TerrainContentsGenerator23, ITerrainContentsGenerator
    {
        public SubsystemTerrain subsystemTerrain;

        public SubsystemGameInfo m_subsystemGameInfo;

        public SubsystemTimeOfDay m_subsystemTimeOfDay;

        public static List<TerrainBrush>[] m_treeBrushesByType;

        public static int[] m_treeTrunksByType;

        public static int[] m_treeLeavesByType;

        public Vector2 temperatureOffset;

        public new int m_seed;

        public Random m_random = new Random();

        public int randomZ;

        public int randomX;

        public SubsystemBlockEntities m_subsystemBlockEntities;

        public static List<TerrainBrush> m_goldbrushes;

        static newTerrainContentsGenerator()
        {
            m_goldbrushes = new List<TerrainBrush>();
            m_treeBrushesByType = new List<TerrainBrush>[EnumUtils.GetEnumValues(typeof(TreeType2)).Max() + 1];
            m_treeTrunksByType = new int[2] { 300, 303 };
            m_treeLeavesByType = new int[2] { 301, 304 };
            Random random = new Random(33);
            m_treeBrushesByType[0] = new List<TerrainBrush>();
            for (int i = 0; i < 16; i++)
            {
                int[] array = new int[16]
                {
                    10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
                    10, 11, 12, 13, 14, 16
                };
                int height5 = array[i];
                int branchesCount = (int)MathUtils.Lerp(10f, 20f, (float)i / 16f);
                TerrainBrush item = CreateTreeBrush(random, GetTreeTrunkValue(TreeType2.Sakura), GetTreeLeavesValue(TreeType2.Sakura), height5, branchesCount, delegate (int y)
                {
                    float num4 = 0.4f;
                    if ((float)y < 0.6f * (float)height5)
                    {
                        num4 = 0f;
                    }
                    else if ((float)y >= 0.6f * (float)height5 && y <= height5)
                    {
                        num4 *= 1.5f;
                    }

                    return num4;
                }, delegate (int y)
                {
                    if ((float)y < (float)height5 * 0.3f || (float)y > (float)height5 * 0.9f)
                    {
                        return 0f;
                    }

                    float num3 = (((float)y < (float)height5 * 0.7f) ? (0.5f * (float)height5) : (0.35f * (float)height5));
                    return random.Float(0.5f, 1f) * num3;
                });
                m_treeBrushesByType[0].Add(item);
            }

            m_treeBrushesByType[1] = new List<TerrainBrush>();
            for (int j = 0; j < 16; j++)
            {
                int[] array2 = new int[16]
                {
                    5, 6, 7, 7, 8, 8, 9, 9, 9, 10,
                    10, 11, 12, 13, 14, 16
                };
                int height4 = array2[j];
                int branchesCount2 = (int)MathUtils.Lerp(10f, 15f, (float)j / 16f);
                TerrainBrush item2 = CreateUniversalTreeBrush(random, m_treeTrunksByType[1], m_treeLeavesByType[1], Terrain.MakeBlockValue(305, 0, 0), height4, branchesCount2, delegate (int y)
                {
                    float num2 = 0.4f;
                    if ((float)y < 0.6f * (float)height4)
                    {
                        num2 = 0f;
                    }
                    else if ((float)y >= 0.6f * (float)height4 && y <= height4)
                    {
                        num2 *= 1.5f;
                    }

                    return num2;
                }, delegate (int y)
                {
                    if ((float)y < (float)height4 * 0.3f || (float)y > (float)height4 * 0.9f)
                    {
                        return 0f;
                    }

                    float num = (((float)y < (float)height4 * 0.7f) ? (0.5f * (float)height4) : (0.35f * (float)height4));
                    return random.Float(0.33f, 1f) * num;
                });
                m_treeBrushesByType[1].Add(item2);
            }
        }

        public static TerrainBrush CreateUniversalTreeBrush(Random random, int woodIndex, int leavesIndex, int friutindex, int height, int branchesCount, Func<int, float> leavesProbabilityByHeight, Func<int, float> branchesLengthByHeight)
        {
            TerrainBrush terrainBrush = new TerrainBrush();
            terrainBrush.AddRay(0, -1, 0, 0, height, 0, 1, 1, 1, woodIndex);
            for (int i = 0; i < branchesCount; i++)
            {
                int x = 0;
                int num = random.Int(0, height);
                int z = 0;
                float num2 = branchesLengthByHeight(num);
                Vector3 vector = Vector3.Normalize(new Vector3(random.Float(-1f, 1f), random.Float(0f, 0.33f), random.Float(-1f, 1f))) * num2;
                int x2 = (int)MathUtils.Round(vector.X);
                int y = num + (int)MathUtils.Round(vector.Y);
                int z2 = (int)MathUtils.Round(vector.Z);
                int cutFace = 0;
                if (MathUtils.Abs(vector.X) == MathUtils.Max(MathUtils.Abs(vector.X), MathUtils.Abs(vector.Y), MathUtils.Abs(vector.Z)))
                {
                    cutFace = 1;
                }
                else if (MathUtils.Abs(vector.Y) == MathUtils.Max(MathUtils.Abs(vector.X), MathUtils.Abs(vector.Y), MathUtils.Abs(vector.Z)))
                {
                    cutFace = 4;
                }

                terrainBrush.AddRay(x, num, z, x2, y, z2, 1, 1, 1, (Func<int?, int?>)((int? v) => v.HasValue ? null : new int?(Terrain.MakeBlockValue(woodIndex, 0, WoodBlock.SetCutFace(0, cutFace)))));
            }

            for (int j = 0; j < 3; j++)
            {
                terrainBrush.CalculateBounds(out var min, out var max);
                for (int k = min.X - 1; k <= max.X + 1; k++)
                {
                    for (int l = min.Z - 1; l <= max.Z + 1; l++)
                    {
                        for (int m = 1; m <= max.Y + 1; m++)
                        {
                            float num3 = leavesProbabilityByHeight(m);
                            if (random.Float(0f, 1f) < num3 && !terrainBrush.GetValue(k, m, l).HasValue && (terrainBrush.CountNonDiagonalNeighbors(k, m, l, leavesIndex) != 0 || terrainBrush.CountNonDiagonalNeighbors(k, m, l, (Func<int?, int>)((int? v) => (v.HasValue && Terrain.ExtractContents(v.Value) == woodIndex) ? 1 : 0)) != 0))
                            {
                                if (new Random().Float(0f, 1f) < 0.8f)
                                {
                                    terrainBrush.AddCell(k, m, l, 0);
                                }
                                else
                                {
                                    terrainBrush.AddCell(k, m, l, friutindex);
                                }
                            }
                        }
                    }
                }

                terrainBrush.Replace(0, leavesIndex);
            }

            terrainBrush.AddCell(0, height, 0, leavesIndex);
            terrainBrush.Compile();
            return terrainBrush;
        }

        public static TerrainBrush CreateMimosaBrush(Random random, float size)
        {
            TerrainBrush terrainBrush = new TerrainBrush();
            int num = m_treeTrunksByType[0];
            int num2 = m_treeLeavesByType[0];
            terrainBrush.AddRay(0, -1, 0, 0, 0, 0, 1, 1, 1, num);
            List<Point3> list = new List<Point3>();
            float num3 = 0f;
            int num4 = 1;
            for (int i = 0; i < num4; i++)
            {
                float radians = 0f;
                Vector3 vector = Vector3.Transform(Vector3.Normalize(new Vector3(0f, random.Float(1f, 1.5f), 0f)), Matrix.CreateRotationY(radians));
                int num5 = random.Int((int)(0.7f * size), (int)size);
                Point3 p = new Point3(0, 0, 0);
                Point3 item = new Point3(Vector3.Round(new Vector3(p) + vector * num5));
                terrainBrush.AddRay(p.X, p.Y, p.Z, item.X, item.Y, item.Z, 1, 1, 1, num);
                list.Add(item);
            }

            foreach (Point3 item2 in list)
            {
                float num6 = random.Float(0.3f * size, 0.45f * size);
                int num7 = (int)MathUtils.Ceiling(num6);
                for (int j = item2.X - num7; j <= item2.X + num7; j++)
                {
                    for (int k = item2.Y - num7; k <= item2.Y + num7; k++)
                    {
                        for (int l = item2.Z - num7; l <= item2.Z + num7; l++)
                        {
                            int num8 = MathUtils.Abs(j - item2.X) + MathUtils.Abs(k - item2.Y) + MathUtils.Abs(l - item2.Z);
                            float num9 = ((new Vector3(j, k, l) - new Vector3(item2)) * new Vector3(1f, 1.7f, 1f)).Length();
                            if (num9 <= num6 && (num6 - num9 > 1f || num8 <= 2 || random.Bool(0.7f)) && !terrainBrush.GetValue(j, k, l).HasValue)
                            {
                                terrainBrush.AddCell(j, k, l, num2);
                            }
                        }
                    }
                }
            }

            terrainBrush.Compile();
            return terrainBrush;
        }

        public newTerrainContentsGenerator(SubsystemTerrain subsystemTerrain)
            : base(subsystemTerrain)
        {
            this.subsystemTerrain = subsystemTerrain;
            float num = (m_islandSize.HasValue ? MathUtils.Min(m_islandSize.Value.X, m_islandSize.Value.Y) : float.MaxValue);
            TGBiomeScaling = ((m_worldSettings.TerrainGenerationMode == TerrainGenerationMode.Island) ? 1f : 1.75f) * m_worldSettings.BiomeSize;
            TGShoreFluctuations = MathUtils.Clamp(2f * num, 0f, 450f);
            TGShoreFluctuationsScaling = MathUtils.Clamp(0.04f * num, 0.5f, 3f);
            TGOceanSlope = 0.006f;
            TGOceanSlopeVariation = 0.004f;
            TGIslandsFrequency = 0.01f;
            TGDensityBias = 55f;
            TGHeightBias = 1f;
            TGRiversStrength = 1f;
            TGMountainsStrength = 255f;
            TGMountainRangeFreq = 0.0006f;
            TGMountainsPercentage = 0.23f;
            TerrainContentsGenerator23.TGMountainsDetailFreq = 0.003f;
            TerrainContentsGenerator23.TGMountainsDetailOctaves = 1;
            TerrainContentsGenerator23.TGMountainsDetailPersistence = 0.01f;
            TGHillsPercentage = 0.3f;
            TGHillsStrength = 2f;
            TGHillsOctaves = 1;
            TGHillsFrequency = 0.01f;
            TGHillsPersistence = 0.1f;
            TGTurbulenceStrength = 20f;
            TGTurbulenceFreq = 0.03f;
            TGTurbulenceOctaves = 1;
            TGTurbulencePersistence = 0.5f;
            TGMinTurbulence = 0.04f;
            TGTurbulenceZero = 0.84f;
            TerrainContentsGenerator23.TGSurfaceMultiplier = 2f;
            TGWater = true;
            TGExtras = true;
            TGCavesAndPockets = true;
        }

        public new void GenerateChunkContentsPass1(TerrainChunk chunk)
        {
            GenerateSurfaceParameters(chunk, 0, 0, 16, 8);
            GenerateTerrain(chunk, 0, 0, 16, 8);
        }

        public new void GenerateChunkContentsPass2(TerrainChunk chunk)
        {
            GenerateSurfaceParameters(chunk, 0, 8, 16, 16);
            GenerateTerrain(chunk, 0, 8, 16, 16);
        }

        public new void GenerateChunkContentsPass3(TerrainChunk chunk)
        {
            GenerateCaves(chunk);
            GeneratePockets(chunk);
            GenerateMinerals(chunk);
            GenerateSurface(chunk);
            PropagateFluidsDownwards(chunk);
        }

        public new void GenerateChunkContentsPass4(TerrainChunk chunk)
        {
            GenerateGrassAndPlants(chunk);
            GenerateLogs(chunk);
            GenerateTrees(chunk);
            GenerateCacti(chunk);
            GeneratePumpkins(chunk);
            GenerateKelp(chunk);
            GenerateSeagrass(chunk);
            GenerateBottomSuckers(chunk);
            GenerateTraps(chunk);
            GenerateIvy(chunk);
            GenerateGraves(chunk);
            GenerateCairns(chunk);
            GenerateSnowAndIce(chunk);
            GenerateBedrockAndAir(chunk);
            UpdateFluidIsTop(chunk);
            GenerateForestTreasureHouse(chunk);
            GenerateNewTrees(chunk);
            GenerateBush2(chunk);
            Wtermelon(chunk);
            GenerateBambooBush(chunk);
            GenerateDesertHugeHouse(chunk);
            GenerateFrozenGiantJail(chunk);
            Tjgc(chunk);
            GenerateForestxmw(chunk);
        }

        public void GenerateForestTreasureHouse(TerrainChunk chunk)
        {
            int x = chunk.Coords.X;
            int y = chunk.Coords.Y;
            Random random = new Random(m_seed + x + 890 * y);
            if (!random.Bool(0.01f) || !(CalculateOceanShoreDistance(chunk.Origin.X, chunk.Origin.Y) > 10f))
            {
                return;
            }

            int num = 10;
            bool flag = true;
            for (int num2 = 200; num2 > 10; num2--)
            {
                if (subsystemTerrain.Terrain.GetCellContentsFast(chunk.Origin.X, num2, chunk.Origin.Y) != 0)
                {
                    num = num2;
                    break;
                }
            }

            for (int i = 0; i < 16; i++)
            {
                for (int j = 0; j < 16; j++)
                {
                    int cellContentsFast = subsystemTerrain.Terrain.GetCellContentsFast(chunk.Origin.X + i, num, chunk.Origin.Y + j);
                    int cellContentsFast2 = subsystemTerrain.Terrain.GetCellContentsFast(chunk.Origin.X + i, num + 1, chunk.Origin.Y + j);
                    int num3 = i + chunk.Origin.X;
                    int num4 = j + chunk.Origin.Y;
                    int num5 = CalculateTemperature(num3, num4);
                    int num6 = CalculateHumidity(num3, num4);
                    if (cellContentsFast == 18 || cellContentsFast == 0 || cellContentsFast2 == 8 || cellContentsFast2 == 3 || cellContentsFast2 == 7 || num5 < 7 || num6 < 8)
                    {
                        flag = false;
                        break;
                    }
                }
            }

            if (flag)
            {
                string text = ContentManager.Get<string>("House/Forest/ForestTreasureHouse");
                text = text.Replace("\n", "#");
                string[] array = text.Split('#');
                string[] array2 = array;
                foreach (string text2 in array2)
                {
                    string[] array3 = text2.Split(',');
                    if (array3.Length > 3)
                    {
                        int num7 = int.Parse(array3[0]);
                        int num8 = int.Parse(array3[1]);
                        int num9 = int.Parse(array3[2]);
                        int value = int.Parse(array3[3]);
                        subsystemTerrain.Terrain.SetCellValueFast(chunk.Origin.X + num7, num + 1 + num8, chunk.Origin.Y + num9, value);
                    }
                }
            }
            else
            {
                GenerateCacti(chunk);
            }
        }

        public void GenerateForestxmw(TerrainChunk chunk)
        {
            int x = chunk.Coords.X;
            int y = chunk.Coords.Y;
            Random random = new Random(m_seed + x + 940 * y);
            if (!random.Bool(0.01f) || !(CalculateOceanShoreDistance(chunk.Origin.X, chunk.Origin.Y) > 10f))
            {
                return;
            }

            int num = 10;
            bool flag = true;
            for (int num2 = 200; num2 > 10; num2--)
            {
                if (subsystemTerrain.Terrain.GetCellContentsFast(chunk.Origin.X, num2, chunk.Origin.Y) != 0)
                {
                    num = num2;
                    break;
                }
            }

            for (int i = 0; i < 16; i++)
            {
                for (int j = 0; j < 16; j++)
                {
                    int cellContentsFast = subsystemTerrain.Terrain.GetCellContentsFast(chunk.Origin.X + i, num, chunk.Origin.Y + j);
                    int cellContentsFast2 = subsystemTerrain.Terrain.GetCellContentsFast(chunk.Origin.X + i, num + 1, chunk.Origin.Y + j);
                    int num3 = i + chunk.Origin.X;
                    int num4 = j + chunk.Origin.Y;
                    int num5 = CalculateTemperature(num3, num4);
                    int num6 = CalculateHumidity(num3, num4);
                    if (cellContentsFast == 18 || cellContentsFast == 0 || cellContentsFast2 == 8 || cellContentsFast2 == 3 || cellContentsFast2 == 7 || num5 < 7 || num6 < 8)
                    {
                        flag = false;
                        break;
                    }
                }
            }

            if (flag)
            {
                string text = ContentManager.Get<string>("House/Forest/xmw");
                text = text.Replace("\n", "#");
                string[] array = text.Split('#');
                string[] array2 = array;
                foreach (string text2 in array2)
                {
                    string[] array3 = text2.Split(',');
                    if (array3.Length > 3)
                    {
                        int num7 = int.Parse(array3[0]);
                        int num8 = int.Parse(array3[1]);
                        int num9 = int.Parse(array3[2]);
                        int value = int.Parse(array3[3]);
                        subsystemTerrain.Terrain.SetCellValueFast(chunk.Origin.X + num7, num + 1 + num8, chunk.Origin.Y + num9, value);
                    }
                }
            }
            else
            {
                GenerateCacti(chunk);
            }
        }

        public void GenerateDesertHugeHouse(TerrainChunk chunk)
        {
            int x = chunk.Coords.X;
            int y = chunk.Coords.Y;
            Random random = new Random((int)MathUtils.Hash((uint)(m_seed + x + 930 * y)));
            if (!(random.Float(0f, 1f) < 0.01f) || !(CalculateOceanShoreDistance(chunk.Origin.X, chunk.Origin.Y) > 10f))
            {
                return;
            }

            int num = 10;
            bool flag = true;
            for (int num2 = 200; num2 > 10; num2--)
            {
                if (subsystemTerrain.Terrain.GetCellContentsFast(chunk.Origin.X, num2, chunk.Origin.Y) != 0)
                {
                    num = num2;
                    break;
                }
            }

            for (int i = 0; i < 16; i++)
            {
                for (int j = 0; j < 16; j++)
                {
                    int num3 = i + chunk.Origin.X;
                    int num4 = j + chunk.Origin.Y;
                    int num5 = CalculateTemperature(num3, num4);
                    int num6 = CalculateHumidity(num3, num4);
                    int cellContentsFast = subsystemTerrain.Terrain.GetCellContentsFast(chunk.Origin.X + i, num, chunk.Origin.Y + j);
                    int cellContentsFast2 = subsystemTerrain.Terrain.GetCellContentsFast(chunk.Origin.X + i, num + 1, chunk.Origin.Y + j);
                    if (cellContentsFast == 18 || cellContentsFast == 0 || cellContentsFast == 4 || cellContentsFast2 == 8 || cellContentsFast2 == 3 || num5 < 8 || num6 > 7)
                    {
                        flag = false;
                        break;
                    }
                }
            }

            if (flag)
            {
                string text = ContentManager.Get<string>("House/Desert/DesertHugeHouse");
                text = text.Replace("\n", "#");
                string[] array = text.Split('#');
                string[] array2 = array;
                foreach (string text2 in array2)
                {
                    string[] array3 = text2.Split(',');
                    if (array3.Length > 3)
                    {
                        int num7 = int.Parse(array3[0]);
                        int num8 = int.Parse(array3[1]);
                        int num9 = int.Parse(array3[2]);
                        int value = int.Parse(array3[3]);
                        subsystemTerrain.Terrain.SetCellValueFast(chunk.Origin.X + num7, num + 1 + num8, chunk.Origin.Y + num9, value);
                    }
                }
            }
            else
            {
                GenerateCacti(chunk);
            }
        }

        public void GenerateFrozenGiantJail(TerrainChunk chunk)
        {
            int x = chunk.Coords.X;
            int y = chunk.Coords.Y;
            Random random = new Random(m_seed + x + 940 * y);
            if (!random.Bool(0.01f) || !(CalculateOceanShoreDistance(chunk.Origin.X, chunk.Origin.Y) > 10f))
            {
                return;
            }

            int num = 10;
            bool flag = true;
            for (int num2 = 200; num2 > 10; num2--)
            {
                if (subsystemTerrain.Terrain.GetCellContentsFast(chunk.Origin.X, num2, chunk.Origin.Y) != 0)
                {
                    num = num2;
                    break;
                }
            }

            for (int i = 0; i < 20; i++)
            {
                for (int j = 0; j < 20; j++)
                {
                    int cellContentsFast = subsystemTerrain.Terrain.GetCellContentsFast(chunk.Origin.X + i, num, chunk.Origin.Y + j);
                    int cellContentsFast2 = subsystemTerrain.Terrain.GetCellContentsFast(chunk.Origin.X + i, num + 1, chunk.Origin.Y + j);
                    int num3 = i + chunk.Origin.X;
                    int num4 = j + chunk.Origin.Y;
                    int num5 = CalculateTemperature(num3, num4);
                    int num6 = CalculateHumidity(num3, num4);
                    if (cellContentsFast == 18 || cellContentsFast2 == 8 || cellContentsFast2 == 3 || cellContentsFast2 == 7 || num5 > 8 || num6 > 4)
                    {
                        flag = false;
                        break;
                    }
                }
            }

            if (flag)
            {
                string text = ContentManager.Get<string>("House/FrozenArea/GiantJail");
                text = text.Replace("\n", "#");
                string[] array = text.Split('#');
                string[] array2 = array;
                foreach (string text2 in array2)
                {
                    string[] array3 = text2.Split(',');
                    if (array3.Length > 3)
                    {
                        int num7 = int.Parse(array3[0]);
                        int num8 = int.Parse(array3[1]);
                        int num9 = int.Parse(array3[2]);
                        int value = int.Parse(array3[3]);
                        subsystemTerrain.Terrain.SetCellValueFast(chunk.Origin.X + num7, num + 1 + num8, chunk.Origin.Y + num9, value);
                    }
                }
            }
            else
            {
                GenerateCacti(chunk);
            }
        }

        public void GenerateNewTrees(TerrainChunk chunk)
        {
            if (!TGExtras)
            {
                return;
            }

            Terrain terrain = m_subsystemTerrain.Terrain;
            _ = chunk.Origin;
            _ = chunk.Origin;
            int x = chunk.Coords.X;
            int y = chunk.Coords.Y;
            for (int i = x; i <= x; i++)
            {
                for (int j = y; j <= y; j++)
                {
                    Random random = new Random(m_seed + i + 3965 * j);
                    int humidity = CalculateHumidity(i * 16, j * 16);
                    int num = CalculateTemperature(i * 16, j * 16);
                    float num2 = MathUtils.Saturate((SimplexNoise.OctavedNoise(i, j, 0.1f, 2, 2f, 0.5f) - 0.25f) / 0.2f + (random.Bool(0.25f) ? 0.5f : 0f));
                    int num3 = (int)(5f * num2);
                    int num4 = 0;
                    for (int k = 0; k < 32; k++)
                    {
                        if (num4 >= num3)
                        {
                            break;
                        }

                        int num5 = i * 16 + random.Int(2, 13);
                        int num6 = j * 16 + random.Int(2, 13);
                        int num7 = terrain.CalculateTopmostCellHeight(num5, num6);
                        if (num7 < 66)
                        {
                            continue;
                        }

                        int cellContentsFast = terrain.GetCellContentsFast(num5, num7, num6);
                        if (cellContentsFast != 2 && cellContentsFast != 8)
                        {
                            continue;
                        }

                        num7++;
                        if (!BlocksManager.Blocks[terrain.GetCellContentsFast(num5 + 1, num7, num6)].IsCollidable && !BlocksManager.Blocks[terrain.GetCellContentsFast(num5 - 1, num7, num6)].IsCollidable && !BlocksManager.Blocks[terrain.GetCellContentsFast(num5, num7, num6 + 1)].IsCollidable && !BlocksManager.Blocks[terrain.GetCellContentsFast(num5, num7, num6 - 1)].IsCollidable)
                        {
                            TreeType2? treeType = GenerateRandomTreeType(random, num + SubsystemWeather.GetTemperatureAdjustmentAtHeight(num7), humidity, num7);
                            if (treeType.HasValue)
                            {
                                ReadOnlyList<TerrainBrush> treeBrushes = GetTreeBrushes(treeType.Value);
                                TerrainBrush terrainBrush = treeBrushes[random.Int(treeBrushes.Count)];
                                terrainBrush.PaintFast(chunk, num5, num7, num6);
                                chunk.AddBrushPaint(num5, num7, num6, terrainBrush);
                            }

                            num4++;
                        }
                    }
                }
            }
        }

        public static TreeType2? GenerateRandomTreeType(Random random, int temperature, int humidity, int y, float densityMultiplier = 1f)
        {
            TreeType2? result = null;
            float num = random.Float() * CalculateTreeProbability(TreeType2.Sakura, temperature, humidity, y);
            float num2 = random.Float() * CalculateTreeProbability(TreeType2.Blue, temperature, humidity, y);
            float num3 = MathUtils.Max(num, num2);
            if (num3 > 0f)
            {
                if (num3 == num)
                {
                    result = TreeType2.Sakura;
                }

                if (num3 == num2)
                {
                    result = TreeType2.Blue;
                }
            }

            if (result.HasValue && random.Bool(densityMultiplier * CalculateTreeDensity(result.Value, temperature, humidity, y)))
            {
                return result;
            }

            return null;
        }

        public static int GetTreeTrunkValue(TreeType2 treeType)
        {
            return m_treeTrunksByType[(int)treeType];
        }

        public static int GetTreeLeavesValue(TreeType2 treeType)
        {
            return m_treeLeavesByType[(int)treeType];
        }

        public static ReadOnlyList<TerrainBrush> GetTreeBrushes(TreeType2 treeType)
        {
            return new ReadOnlyList<TerrainBrush>(m_treeBrushesByType[(int)treeType]);
        }

        public static float CalculateTreeDensity(TreeType2 treeType, int temperature, int humidity, int y)
        {
            switch (treeType)
            {
                case TreeType2.Sakura:
                case TreeType2.Blue:
                    return RangeProbability(humidity, 4f, 15f, 15f, 15f);
                default:
                    return 0f;
            }
        }

        public static float CalculateTreeProbability(TreeType2 treeType, int temperature, int humidity, int y)
        {
            switch (treeType)
            {
                case TreeType2.Sakura:
                    return RangeProbability(temperature, 4f, 10f, 15f, 15f) * RangeProbability(humidity, 6f, 8f, 15f, 15f) * RangeProbability(y, 0f, 0f, 82f, 87f);
                case TreeType2.Blue:
                    return 0.25f * RangeProbability(temperature, 0f, 0f, 6f, 10f) * RangeProbability(humidity, 9f, 11f, 15f, 15f) * RangeProbability(y, 0f, 0f, 95f, 100f);
                default:
                    return 0f;
            }
        }


        public static float RangeProbability(float v, float a, float b, float c, float d)
        {
            if (v < a)
            {
                return 0f;
            }

            if (v < b)
            {
                return (v - a) / (b - a);
            }

            if (v <= c)
            {
                return 1f;
            }

            if (v <= d)
            {
                return 1f - (v - c) / (d - c);
            }

            return 0f;
        }

        public static TerrainBrush CreateTreeBrush(Random random, int woodIndex, int leavesIndex, int height, int branchesCount, Func<int, float> leavesProbabilityByHeight, Func<int, float> branchesLengthByHeight)
        {
            TerrainBrush terrainBrush = new TerrainBrush();
            terrainBrush.AddRay(0, -1, 0, 0, height, 0, 1, 1, 1, woodIndex);
            for (int i = 0; i < branchesCount; i++)
            {
                int x = 0;
                int num = random.Int(0, height);
                int z = 0;
                float num2 = branchesLengthByHeight(num);
                Vector3 vector = Vector3.Normalize(new Vector3(random.Float(-1f, 1f), random.Float(0f, 0.33f), random.Float(-1f, 1f))) * num2;
                int x2 = (int)MathUtils.Round(vector.X);
                int y = num + (int)MathUtils.Round(vector.Y);
                int z2 = (int)MathUtils.Round(vector.Z);
                int cutFace = 0;
                if (MathUtils.Abs(vector.X) == MathUtils.Max(MathUtils.Abs(vector.X), MathUtils.Abs(vector.Y), MathUtils.Abs(vector.Z)))
                {
                    cutFace = 1;
                }
                else if (MathUtils.Abs(vector.Y) == MathUtils.Max(MathUtils.Abs(vector.X), MathUtils.Abs(vector.Y), MathUtils.Abs(vector.Z)))
                {
                    cutFace = 4;
                }

                terrainBrush.AddRay(x, num, z, x2, y, z2, 1, 1, 1, (Func<int?, int?>)((int? v) => v.HasValue ? null : new int?(Terrain.MakeBlockValue(woodIndex, 0, WoodBlock.SetCutFace(0, cutFace)))));
            }

            for (int j = 0; j < 3; j++)
            {
                terrainBrush.CalculateBounds(out var min, out var max);
                for (int k = min.X - 1; k <= max.X + 1; k++)
                {
                    for (int l = min.Z - 1; l <= max.Z + 1; l++)
                    {
                        for (int m = 1; m <= max.Y + 1; m++)
                        {
                            float num3 = leavesProbabilityByHeight(m);
                            if (random.Float(0f, 1f) < num3 && !terrainBrush.GetValue(k, m, l).HasValue && (terrainBrush.CountNonDiagonalNeighbors(k, m, l, leavesIndex) != 0 || terrainBrush.CountNonDiagonalNeighbors(k, m, l, (Func<int?, int>)((int? v) => (v.HasValue && Terrain.ExtractContents(v.Value) == woodIndex) ? 1 : 0)) != 0))
                            {
                                terrainBrush.AddCell(k, m, l, 0);
                            }
                        }
                    }
                }

                terrainBrush.Replace(0, leavesIndex);
            }

            terrainBrush.AddCell(0, height, 0, leavesIndex);
            terrainBrush.Compile();
            return terrainBrush;
        }

        public void GenerateBush2(TerrainChunk chunk)
        {
            if (!TGExtras)
            {
                return;
            }

            int x = chunk.Coords.X;
            int y = chunk.Coords.Y;
            Random random = new Random(m_seed + x + 900 * y);
            if (!random.Bool(0.1f))
            {
                return;
            }

            int num = random.Int(1, 16);
            for (int i = 0; i < num; i++)
            {
                int num2 = random.Int(1, 14);
                int num3 = random.Int(1, 14);
                int humidityFast = chunk.GetHumidityFast(num2, num3);
                int temperatureFast = chunk.GetTemperatureFast(num2, num3);
                if (humidityFast < 10 || temperatureFast <= 6)
                {
                    continue;
                }

                for (int j = 0; j < 16; j++)
                {
                    int x2 = num2 + random.Int(-1, 1);
                    int z = num3 + random.Int(-1, 1);
                    for (int num4 = 254; num4 >= 0; num4--)
                    {
                        switch (Terrain.ExtractContents(chunk.GetCellValueFast(x2, num4, z)))
                        {
                            case 8:
                                chunk.SetCellValueFast(x2, num4 + 1, z, random.Bool(0.25f) ? Terrain.MakeBlockValue(321, 0, 0) : Terrain.MakeBlockValue(25));
                                break;
                            case 0:
                                continue;
                        }

                        break;
                    }
                }
            }
        }

        public void Wtermelon(TerrainChunk chunk)
        {
            if (!TGExtras)
            {
                return;
            }

            int x = chunk.Coords.X;
            int y = chunk.Coords.Y;
            Random random = new Random(m_seed + x + 910 * y);
            if (!random.Bool(0.6f))
            {
                return;
            }

            int num = random.Int(0, MathUtils.Max(1, 1));
            for (int i = 0; i < num; i++)
            {
                int num2 = random.Int(1, 14);
                int num3 = random.Int(1, 14);
                int humidityFast = chunk.GetHumidityFast(num2, num3);
                int temperatureFast = chunk.GetTemperatureFast(num2, num3);
                if (humidityFast < 10 || temperatureFast <= 6)
                {
                    continue;
                }

                for (int j = 0; j < 1; j++)
                {
                    int x2 = num2 + random.Int(-1, 1);
                    int z = num3 + random.Int(-1, 1);
                    for (int num4 = 254; num4 >= 0; num4--)
                    {
                        switch (Terrain.ExtractContents(chunk.GetCellValueFast(x2, num4, z)))
                        {
                            case 8:
                                chunk.SetCellValueFast(x2, num4 + 1, z, Terrain.MakeBlockValue(323));
                                break;
                            case 0:
                                continue;
                        }

                        break;
                    }
                }
            }
        }

        public void GenerateBambooBush(TerrainChunk chunk)
        {
            if (!TGExtras)
            {
                return;
            }

            int x = chunk.Coords.X;
            int y = chunk.Coords.Y;
            Random random = new Random(m_seed + x + 920 * y);
            if (!random.Bool(0.1f))
            {
                return;
            }

            int num = random.Int(1, 16);
            for (int i = 0; i < num; i++)
            {
                int num2 = random.Int(1, 14);
                int num3 = random.Int(1, 14);
                int humidityFast = chunk.GetHumidityFast(num2, num3);
                int temperatureFast = chunk.GetTemperatureFast(num2, num3);
                for (int j = 0; j < 16; j++)
                {
                    int x2 = num2 + random.Int(-1, 1);
                    int z = num3 + random.Int(-1, 1);
                    for (int num4 = 254; num4 >= 0; num4--)
                    {
                        switch (Terrain.ExtractContents(chunk.GetCellValueFast(x2, num4, z)))
                        {
                            case 8:
                                chunk.SetCellValueFast(x2, num4 + 1, z, Terrain.MakeBlockValue(334));
                                chunk.SetCellValueFast(x2, num4 + 2, z, Terrain.MakeBlockValue(334));
                                chunk.SetCellValueFast(x2, num4 + 3, z, Terrain.MakeBlockValue(334));
                                break;
                            case 0:
                                continue;
                        }

                        break;
                    }
                }
            }
        }

        public void Tjgc(TerrainChunk chunk)
        {
            if (!TGExtras)
            {
                return;
            }

            int x = chunk.Coords.X;
            int y = chunk.Coords.Y;
            Random random = new Random(m_seed + x + 930 * y);
            if (!random.Bool(0.55f))
            {
                return;
            }

            int num = random.Int(0, MathUtils.Max(1, 2));
            for (int i = 0; i < num; i++)
            {
                int num2 = random.Int(1, 14);
                int num3 = random.Int(1, 14);
                int humidityFast = chunk.GetHumidityFast(num2, num3);
                int temperatureFast = chunk.GetTemperatureFast(num2, num3);
                if (humidityFast < 10 || temperatureFast <= 6)
                {
                    continue;
                }

                for (int j = 0; j < 1; j++)
                {
                    int x2 = num2 + random.Int(-1, 1);
                    int z = num3 + random.Int(-1, 1);
                    for (int num4 = 254; num4 >= 0; num4--)
                    {
                        switch (Terrain.ExtractContents(chunk.GetCellValueFast(x2, num4, z)))
                        {
                            case 8:
                                chunk.SetCellValueFast(x2, num4 + 1, z, Terrain.MakeBlockValue(357));
                                break;
                            case 0:
                                continue;
                        }

                        break;
                    }
                }
            }
        }
    }
}